#include "FSMC_SRAM.h"
#include "stm32f4xx.h"
#include "print_rtt.h"
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
// -------------------------- 辅助函数：GPIO复用配置（FSMC_AF12） --------------------------

static void FSMC_SRAM_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    // 1. 使能GPIO时钟（PD/PE/PF/PG）和FSMC时钟（AHB3总线）
    RCC_AHB1PeriphClockCmd(
        RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE |
            RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG,
        ENABLE);
    RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC, ENABLE); // FSMC时钟使能

    // -------------------------- 数据线配置（FSMC_D0~D15）：复用AF12 --------------------------
    // PD14(D0)、PD15(D1)、PD0(D2)、PD1(D3)、PD8(D13)、PD9(D14)、PD10(D15)
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 | GPIO_Pin_9 |
                               GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;       // 复用模式
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;     // 推挽输出
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; // 高速（匹配FSMC速率）
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;   // 浮空（数据线无需上下拉）
    GPIO_Init(GPIOD, &GPIO_InitStruct);
    // 配置AF12（FSMC的复用功能）
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_FSMC);

    // PE7(D4)、PE8(D5)、PE9(D6)、PE10(D7)、PE11(D8)、PE12(D9)、PE13(D10)、PE14(D11)、PE15(D12)
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 |
                               GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_Init(GPIOE, &GPIO_InitStruct);
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource7, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource8, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource9, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource12, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource15, GPIO_AF_FSMC);

    // -------------------------- 地址线配置（FSMC_A0~A17）：复用AF12 --------------------------
    // PF0(A0)、PF1(A1)、PF2(A2)、PF3(A3)、PF4(A4)、PF5(A5)、PF12(A6)、PF13(A7)、PF14(A8)、PF15(A9)
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 |
                               GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_12 | GPIO_Pin_13 |
                               GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_Init(GPIOF, &GPIO_InitStruct);
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource0, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource1, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource2, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource3, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource4, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource5, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource12, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource13, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource14, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource15, GPIO_AF_FSMC);

    // PG0(A10)、PG1(A11)、PG2(A12)、PG3(A13)、PG4(A14)、PG5(A15)、PD11(A16)、PD12(A17)
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 |
                               GPIO_Pin_4 | GPIO_Pin_5;
    GPIO_Init(GPIOG, &GPIO_InitStruct);
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource0, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource1, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource2, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource3, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource4, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource5, GPIO_AF_FSMC);

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
    GPIO_Init(GPIOD, &GPIO_InitStruct);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource11, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_FSMC);

    // -------------------------- 控制线配置（FSMC_NE2/NBL0/NBL1/NOE/NWE）：复用AF12 --------------------------
    // PG10(FSMC_NE2：片选)
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_Init(GPIOG, &GPIO_InitStruct);
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource10, GPIO_AF_FSMC);

    // PE0(FSMC_NBL0：低字节)、PE1(FSMC_NBL1：高字节)
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_Init(GPIOE, &GPIO_InitStruct);
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource0, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource1, GPIO_AF_FSMC);

    // PD4(FSMC_NOE：读使能)、PD5(FSMC_NWE：写使能)
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
    GPIO_Init(GPIOD, &GPIO_InitStruct);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_FSMC);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_FSMC);
}

// -------------------------- FSMC控制器配置（异步SRAM时序） --------------------------
int FSMC_SRAM_Init(void)
{
    FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStruct;
    FSMC_NORSRAMTimingInitTypeDef FSMC_ReadTimingStruct;
    FSMC_NORSRAMTimingInitTypeDef FSMC_WriteTimingStruct;

    // 1. 初始化GPIO（复用为FSMC）
    FSMC_SRAM_GPIO_Init();

    // 2. 配置读时序（匹配IS61WV25616 10ns规格）
    // HCLK=168MHz，周期≈5.95ns；时序参数需满足SRAM手册要求
    FSMC_ReadTimingStruct.FSMC_AddressSetupTime = 2;           // 地址建立时间：2×5.95≈11.9ns（≥10ns）
    FSMC_ReadTimingStruct.FSMC_AddressHoldTime = 0;            // 地址保持时间：0ns（≥0ns）
    FSMC_ReadTimingStruct.FSMC_DataSetupTime = 2;              // 数据建立时间：2×5.95≈11.9ns（≥10ns）
    FSMC_ReadTimingStruct.FSMC_BusTurnAroundDuration = 0;      // 总线 turnaround时间：0（无需）
    FSMC_ReadTimingStruct.FSMC_CLKDivision = 0;                // 时钟分频：0（异步模式无CLK）
    FSMC_ReadTimingStruct.FSMC_DataLatency = 0;                // 数据延迟：0（异步模式）
    FSMC_ReadTimingStruct.FSMC_AccessMode = FSMC_AccessMode_A; // 访问模式A

    // 3. 配置写时序（与读时序一致，SRAM读写时序相同）
    FSMC_WriteTimingStruct.FSMC_AddressSetupTime = 2;
    FSMC_WriteTimingStruct.FSMC_AddressHoldTime = 0;
    FSMC_WriteTimingStruct.FSMC_DataSetupTime = 2;
    FSMC_WriteTimingStruct.FSMC_BusTurnAroundDuration = 0;
    FSMC_WriteTimingStruct.FSMC_CLKDivision = 0;
    FSMC_WriteTimingStruct.FSMC_DataLatency = 0;
    FSMC_WriteTimingStruct.FSMC_AccessMode = FSMC_AccessMode_A;

    // 4. 配置FSMC_NOR/SRAM核心参数（Bank1 Zone2：NE2）
    FSMC_NORSRAMInitStruct.FSMC_Bank = FSMC_Bank1_NORSRAM3;                               // 对应NE2片选
    FSMC_NORSRAMInitStruct.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;             // 地址/数据总线分离
    FSMC_NORSRAMInitStruct.FSMC_MemoryType = FSMC_MemoryType_SRAM;                        // 内存类型：SRAM
    FSMC_NORSRAMInitStruct.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;               // 数据宽度：16位
    FSMC_NORSRAMInitStruct.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;           // 禁止突发访问（异步）
    FSMC_NORSRAMInitStruct.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;         // 禁止异步等待
    FSMC_NORSRAMInitStruct.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;         // 等待信号极性：低
    FSMC_NORSRAMInitStruct.FSMC_WrapMode = FSMC_WrapMode_Disable;                         // 禁止_wrap模式
    FSMC_NORSRAMInitStruct.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState; // 等待信号激活时机
    FSMC_NORSRAMInitStruct.FSMC_WriteOperation = FSMC_WriteOperation_Enable;              // 使能写操作
    FSMC_NORSRAMInitStruct.FSMC_WaitSignal = FSMC_WaitSignal_Disable;                     // 禁止等待信号
    FSMC_NORSRAMInitStruct.FSMC_ExtendedMode = FSMC_ExtendedMode_Enable;                  // 使能扩展模式（读写时序分开配置）
    FSMC_NORSRAMInitStruct.FSMC_WriteBurst = FSMC_WriteBurst_Disable;                     // 禁止写突发
    FSMC_NORSRAMInitStruct.FSMC_ReadWriteTimingStruct = &FSMC_ReadTimingStruct;           // 读时序
    FSMC_NORSRAMInitStruct.FSMC_WriteTimingStruct = &FSMC_WriteTimingStruct;              // 写时序

    // 5. 初始化FSMC
    FSMC_NORSRAMInit(&FSMC_NORSRAMInitStruct);

    //    // 6. 使能FSMC Bank1 Zone2（激活SRAM）
    FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3, ENABLE);
    if (sram_512k_check() != 0)
    {
        LOG_ERROR("SRAM check fail!\r\n");
        return 1;
    }
    return 0;
}

// -------------------------- 单地址写（16位数据） --------------------------
void FSMC_SRAM_Write(uint32_t addr, uint16_t data)
{
    if (addr >= FSMC_SRAM_SIZE / 2)
    { // 16位数据：地址单位为“半字”，最大地址=512KB/2=256K=0x40000？不对：SRAM_SIZE=0x80000字节=512KB，16位数据对应0x40000个地址（0~0x3FFFF）
        LOG_INFO("FSMC SRAM Write Error: Address 0x%05X out of range!\r\n", addr);
        return;
    }
    FSMC_SRAM_PTR[addr] = data; // 直接通过映射指针写数据（硬件自动控制FSMC时序）
}

// -------------------------- 单地址读（16位数据） --------------------------
uint16_t FSMC_SRAM_Read(uint32_t addr)
{
    if (addr >= FSMC_SRAM_SIZE / 2)
    {
        LOG_INFO("FSMC SRAM Read Error: Address 0x%05X out of range!\r\n", addr);
        return 0xFFFF;
    }
    return FSMC_SRAM_PTR[addr]; // 直接通过映射指针读数据
}

// -------------------------- 批量写（缓冲区） --------------------------
void FSMC_SRAM_WriteBuffer(uint32_t start_addr, uint16_t *buf, uint32_t len)
{
    uint32_t i;
    if ((start_addr + len) > (FSMC_SRAM_SIZE / 2))
    {
        LOG_INFO("FSMC SRAM Write Buffer Error: Out of range!\r\n");
        return;
    }
    for (i = 0; i < len; i++)
    {
        FSMC_SRAM_PTR[start_addr + i] = buf[i];
    }
}

// -------------------------- 批量读（缓冲区） --------------------------
void FSMC_SRAM_ReadBuffer(uint32_t start_addr, uint16_t *buf, uint32_t len)
{
    uint32_t i;
    if ((start_addr + len) > (FSMC_SRAM_SIZE / 2))
    {
        LOG_INFO("FSMC SRAM Read Buffer Error: Out of range!\r\n");
        return;
    }
    for (i = 0; i < len; i++)
    {
        buf[i] = FSMC_SRAM_PTR[start_addr + i];
    }
}

// -------------------------- 全容量检测参数（IS61WV25616） --------------------------

void sram_write(void *dst, void *src, uint32_t n)
{
    volatile uint8_t *d = (volatile uint8_t *)dst;
    const uint8_t *s = (uint8_t *)src;
    while (n--)
        *d++ = *s++;
}
void sram_read(void *dst, void *src, uint32_t n)
{
    volatile uint8_t *d = (volatile uint8_t *)dst;
    const uint8_t *s = (uint8_t *)src;
    while (n--)
        *d++ = *s++;
}
/* 零硬件修复：16-bit 字对齐拷贝，MCU A0 不接也稳 */
void sram_write16(void *dst, void *src, uint32_t len16)
{
    volatile uint16_t *d = (volatile uint16_t *)dst;
    uint16_t *s = (uint16_t *)src;
    for (; len16; len16--)
        *d++ = *s++;
}

void sram_read16(void *dst, void *src, uint32_t len16)
{
    volatile uint16_t *s = (volatile uint16_t *)src;
    uint16_t *d = (uint16_t *)dst;
    for (; len16; len16--)
        *d++ = *s++;
}

volatile uint16_t *sram = (volatile uint16_t *)0x68000000; // NE3 base

/* -------------------- 测试参数 -------------------- */
#define SRAM_WORDS (256U * 1024U) // 256 K words = 512 KB
#define STEP_256B (256U / 2U)     // 256 bytes → 128 words
#define STEP_238B (238U / 2U)     // 238 bytes → 119 words

/* ===================================================================
 * 1. 背景填充：0x00 00 01 00 02 00 … FF 00 (512 KB total)
 * =================================================================== */
static void sram_fill_bg(void)
{
    // LOG_INFO("=== Filling background 0x00-0xFF cycle ===\r\n");
    for (uint32_t i = 0; i < SRAM_WORDS; i++)
        sram[i] = i & 0xFFU; // low byte cycles, high byte = 0
    // LOG_INFO("Background fill complete\r\n");
}

/* ===================================================================
 * 2. 256-byte block test: replace with 0xFFFF, verify no overlay
 * =================================================================== */
static uint8_t sram_256b_check(void)
{
    uint16_t new_pat = 0xFFFFU;
    uint32_t step_w = STEP_256B; // words in 256 B
    // LOG_INFO("=== 256-byte block check (0xFFFF) ===\r\n");

    for (uint32_t offs = 0; offs < SRAM_WORDS; offs += step_w)
    {
        /* record background outside the block */
        uint32_t pre_offs = (offs == 0) ? (SRAM_WORDS - 1) : (offs - 1);
        uint32_t post_offs = (offs + step_w >= SRAM_WORDS) ? 0 : (offs + step_w);
        uint16_t pre_bg = sram[pre_offs];
        uint16_t post_bg = sram[post_offs];

        /* write new pattern inside the block */
        for (uint32_t j = 0; j < step_w; j++)
            sram[offs + j] = new_pat;

        /* verify inside = new pattern */
        for (uint32_t j = 0; j < step_w; j++)
        {
            if (sram[offs + j] != new_pat)
            {
                LOG_ERROR("256B FAIL @ 0x%08X  exp=0x%04X act=0x%04X\r\n",
                          0x68000000 + (offs + j) * 2, new_pat, sram[offs + j]);
                return 1;
            }
        }

        /* verify outside = original background */
        if (sram[pre_offs] != pre_bg || sram[post_offs] != post_bg)
        {
            LOG_ERROR("256B OVERLAY @ 0x%08X  pre=0x%04X act=0x%04X\r\n",
                      0x68000000 + pre_offs * 2, pre_bg, sram[pre_offs]);
            return 1;
        }

        /* restore background (no-overlay) */
        for (uint32_t j = 0; j < step_w; j++)
            sram[offs + j] = (offs + j) & 0xFFU;
    }
    LOG_INFO("256-byte block check PASS\r\n");
    return 0;
}

/* ===================================================================
 * 3. 238-byte block test: replace with 0x0000, verify no overlay
 * =================================================================== */
static uint8_t sram_238b_check(void)
{
    uint16_t new_pat = 0x0000U;
    uint32_t step_w = STEP_238B; // words in 238 B
    // LOG_INFO("=== 238-byte block check (0x0000) ===\r\n");

    for (uint32_t offs = 0; offs < SRAM_WORDS; offs += step_w)
    {
        uint32_t pre_offs = (offs == 0) ? (SRAM_WORDS - 1) : (offs - 1);
        uint32_t post_offs = (offs + step_w >= SRAM_WORDS) ? 0 : (offs + step_w);
        uint16_t pre_bg = sram[pre_offs];
        uint16_t post_bg = sram[post_offs];

        /* write new pattern */
        for (uint32_t j = 0; j < step_w; j++)
            sram[offs + j] = new_pat;

        /* verify inside */
        for (uint32_t j = 0; j < step_w; j++)
        {
            if (sram[offs + j] != new_pat)
            {
                LOG_ERROR("238B FAIL @ 0x%08X  exp=0x%04X act=0x%04X\r\n",
                          0x68000000 + (offs + j) * 2, new_pat, sram[offs + j]);
                return 1;
            }
        }

        /* verify outside */
        if (sram[pre_offs] != pre_bg || sram[post_offs] != post_bg)
        {
            LOG_ERROR("238B OVERLAY @ 0x%08X  pre=0x%04X act=0x%04X\r\n",
                      0x68000000 + pre_offs * 2, pre_bg, sram[pre_offs]);
            return 1;
        }

        /* restore background */
        for (uint32_t j = 0; j < step_w; j++)
            sram[offs + j] = (offs + j) & 0xFFU;
    }
    LOG_INFO("238-byte block check PASS\r\n");
    return 0;
}

/* ===================================================================
 * 4. One-shot entry point
 * =================================================================== */
int sram_512k_check(void)
{
    sram_fill_bg();
    if (sram_256b_check() != 0)
    {
        LOG_ERROR(">>> 256B check FAILED <<<<\r\n");
        return 1;
    }
    if (sram_238b_check() != 0)
    {
        LOG_ERROR(">>> 238B check FAILED <<<<\r\n");
        return 1;
    }
    LOG_INFO(">>> 512 KB check ALL PASS <<<<\r\n");
    return 0;
}
